#!/usr/local/bin/php
<?php

/*
 * Copyright (C) 2017-2019 Franco Fichtner <franco@opnsense.org>
 * Copyright (C) 2006 Scott Ullrich <sullrich@gmail.com>
 * Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

require_once("config.inc");
require_once("auth.inc");
require_once("filter.inc");
require_once("rrd.inc");
require_once("util.inc");
require_once("system.inc");
require_once("interfaces.inc");

$argument = isset($argv[1]) ? trim($argv[1]) : '';

if (file_exists('/var/run/booting')) {
    log_error("IP renewal deferred during boot on '{$argument}'");
    file_put_contents('/tmp/newwanipv6_' . $argument, $argument);
    return;
}

log_error("IPv6 renewal is starting on '{$argument}'");

if (empty($argument)) {
    $interface = 'wan';
    $interface_real = get_real_interface($interface, 'inet6');
} else {
    $interface = convert_real_interface_to_friendly_interface_name($argument);
    $interface_real = $argument;
}

$ip = get_interface_ipv6($interface);

if (!isset($config['interfaces'][$interface]['enable'])) {
    log_error("Interface '{$interface}' is disabled or empty, nothing to do.");
    return;
}

$interface_descr = convert_friendly_interface_to_friendly_descr($interface);

log_error("On (IP address: {$ip}) (interface: {$interface_descr}[{$interface}]) (real interface: {$interface_real}).");

/*
 * Take care of OpenVPN and similar if you generate the event
 * to reconfigure an interface.  OpenVPN might be in tap(4)
 * mode and not have an IP address.
 */
if ((empty($ip) || !is_ipaddr($ip)) && substr($interface_real, 0, 4) != 'ovpn') {
    log_error("Failed to detect IP for {$interface_descr}[{$interface}]");
    return;
}

$configip = $config['interfaces'][$interface]['ipaddrv6'];

$searchdomain_file = "/var/etc/searchdomain_v6{$interface_real}";
$nameserver_file = "/var/etc/nameserver_v6{$interface_real}";
$cacheip_file = "/var/db/{$interface}_cacheipv6";
$ip_file = "/var/db/{$interface}_ipv6";

$new_domain_name_servers = getenv('new_domain_name_servers');
if (!empty($new_domain_name_servers)) {
    $name_servers = explode(" ", $new_domain_name_servers);
    $valid_ns = array();
    foreach ($name_servers as $ns) {
        if (is_ipaddr(trim($ns))) {
            $valid_ns[] = trim($ns);
        }
    }

    if (count($valid_ns) > 0) {
        @file_put_contents($nameserver_file, implode("\n", $valid_ns));
    }
}

$new_domain_name = getenv('new_domain_name');
if (!empty($new_domain_name)) {
    @file_put_contents($searchdomain_file, $new_domain_name);
}

if (is_ipaddr($ip)) {
    @file_put_contents($ip_file, $ip);
}

interfaces_vips_configure(false, $interface);

if (count(link_interface_to_track6($interface, true))) {
    plugins_configure('dhcp', false, array('inet6'));
}

system_resolvconf_generate();
system_hosts_generate();

$cacheip = @file_get_contents($cacheip_file);

if (!is_ipaddr($cacheip) || $ip != $cacheip || !is_ipaddr($configip)) {
    if (is_ipaddr($ip)) {
        if ($ip == $cacheip) {
            if (in_array($config['interfaces'][$interface]['ipaddr'], array('l2tp', 'ppp', 'pppoe', 'pptp'))) {
                /* PPP reconnect loop avoidance */
                return;
            }
        } else {
            if (is_ipaddr($cacheip) && does_interface_exist($interface_real)) {
                mwexec("/sbin/ifconfig {$interface_real} inet6 {$cacheip} delete");
            }
        }
    }

    @unlink($cacheip_file);

    system_routing_configure(false, $interface);
    plugins_configure('monitor');
    filter_configure_sync();

    if (is_ipaddr($ip)) {
        @file_put_contents($cacheip_file, $ip);
    }

    plugins_configure('vpn', false, array($interface));
    plugins_configure('newwanip', false, array($interface));
    rrd_configure();
}
